﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Configuration;

using Db4objects.Db4o;
using Db4objects.Db4o.Config;

using Db4o.Framework.Business;
using Db4o.Framework.Interfaces;
using Db4o.Framework.Exceptions;
using Db4o.Framework.Configuration;

namespace Db4o.Framework
{
    /// <summary>
    /// Initialization class used to configure Business assembly and Db4o.Framework settings
    /// </summary>
    public sealed class CoreInitializer : ILogged
    {
       
        #region Design pattern : << Singleton CoreInitializer >>

        // read-only private member
        private static readonly CoreInitializer instance = new CoreInitializer();

	    // private construtor
        private CoreInitializer() {
            try
            {
            }
            catch (Exception e)
            {
                ExceptionManager.Instance.ThrowFatalLogException("CoreInitializationException", "Configuration file not found",e);

            }
        }

	    // public property
        public static CoreInitializer Instance { get { return instance; } }

        #endregion


        private int db4oDebugLevel;
        public int Db4oDebugLevel
        {
            get { return db4oDebugLevel; }
            set { db4oDebugLevel = value; }
        }
        private ConnexionStrategy strategy;
        internal ConnexionStrategy Strategy
        {
            get { return strategy; }
            set { strategy = value; }
        }

        /// <summary>
        /// Init the BusinessAssembly and configure Factory, generate uuid by default
        /// </summary>
        /// <param name="assembly">path to the assembly</param>
        private void ConfigureBusinessAssembly(string assembly)
        {
            ConfigureBusinessAssembly(assembly, true);
        }
        /// <summary>
        /// Init the BusinessAssembly and configure Factory
        /// </summary>
        /// <param name="assembly">path to the assembly</param>
        /// <param name="uuid">generate uuid</param>
        private void ConfigureBusinessAssembly(string assembly, bool uuid)
        {

            logger.DebugFormat("ConfigureBusinessAssembly Business assembly [{0}]", assembly);
            
            BusinessManager.Instance.BusinessAssembly = Assembly.Load(assembly);

            if (uuid)
                Db4oFactory.Configure().GenerateUUIDs(int.MaxValue);

            Db4oFactory.Configure().Queries().EvaluationMode(QueryEvaluationMode.LAZY);
            Db4oFactory.Configure().MessageLevel(Db4oDebugLevel);
            Db4oFactory.Configure().SingleThreadedClient(Convert.ToBoolean(AssemblySettings.Default["SingleClientAccess"]));

            foreach (Type type in BusinessManager.Instance.ManagedTypes)
            {
                Db4oFactory.Configure().ObjectClass(type).CascadeOnUpdate(true);
                Db4oFactory.Configure().ObjectClass(type).CascadeOnActivate(true);
           }
        }

        public void Configure(string configurationFile)
        {
            try
            {
                // config file
                Configuration.AssemblySettings.Default.ConfigurationFile = configurationFile;
                // debug
                log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(Configuration.AssemblySettings.Default.ConfigurationFile));
                Db4oDebugLevel = Int32.Parse(AssemblySettings.Default["Db4oDebugLevel"]);
                // assembly settings
                ConfigureBusinessAssembly(AssemblySettings.Default["BusinessAssembly"]);
            }
            catch (Exception e)
            {
                ExceptionManager.Instance.ThrowFatalLogException("system", "Configure()", e);

            }
        }
       
       /// <summary>
       /// Load database file 
       /// </summary>
       /// <param name="database">file of database</param>
       /// <param name="overfile">override existing file</param>
        public void Load(string database, bool overfile)
        {
            LocalDatabaseStrategy localStrategy = new LocalDatabaseStrategy(database);
            localStrategy.Connect();
        }
        /// <summary>
        /// Load a remote database connexion server
        /// </summary>
        /// <param name="host">host to connect</param>
        /// <param name="port">listening port</param>
        /// <param name="user">user</param>
        /// <param name="password">password</param>
        public void Load(string host, int port, string user, string password)
        {
            RemoteConnexionStrategy remoteStrategy = new RemoteConnexionStrategy(host, port, user, password);
            remoteStrategy.Connect();
        }
        public void Load()
        {
            try
            {
                if (bool.Parse(AssemblySettings.Default["ServerMode"]).Equals(true))
                {
                    Strategy = new RemoteConnexionStrategy(
                        AssemblySettings.Default["Host"],
                        Int32.Parse(AssemblySettings.Default["Port"]),
                        AssemblySettings.Default["User"],
                        AssemblySettings.Default["Pass"]
                        );
                }
                else
                {
                    Strategy = new LocalDatabaseStrategy(AssemblySettings.Default["DatabaseFile"]);
                }
                Strategy.Connect();
            }
            catch (Exception)
            {
                throw;
            }

        }
        
    }
}
